/*
 * Copyright 2008 Max Kugland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.splink.asbeangen.templates.as3;

import java.util.List;

import org.splink.asbeangen.templates.ClassTemplateHelper;
import org.splink.asbeangen.templates.IClassTemplate;
import org.splink.asbeangen.templates.ITemplateDataClass;

public class AS3DataClass extends AS3Class implements ITemplateDataClass {
	private String _originalClassName;
	private boolean _hasToXML;

	public AS3DataClass(List<String> copyright, String packagename, String classname, List<String> interfazes,
			String ifazeBasePackage, IClassTemplate template, boolean hasToXML) {
		super(copyright, packagename, ClassTemplateHelper.firstCharToUpperCase(classname) + DATA_CLASS_POSTFIX,
				interfazes, ifazeBasePackage, template);
		_originalClassName = classname;
		_hasToXML = hasToXML;
	}

	public void addToConstructor(String name, String type, int vartype) {
	}

	public void addToMethods(String name, String type, int vartype) {
		if (vartype == AS3Class.VAR_TYPE_CUSTOM) {
			name += DATA_CLASS_POSTFIX;
			type = handleCustomType(type + DATA_CLASS_POSTFIX);
		} else if (vartype == AS3Class.VAR_TYPE_PCDATA) {
			name = "content";
			type = "String";
		}

		String gMethod = _template.getGetMethod(name, type);
		String sMethod = _template.getSetMethod(name, type);
		if (!_methods.contains(gMethod)) {
			_methods += gMethod;
		}
		if (!_methods.contains(sMethod)) {
			_methods += sMethod;
		}
	}

	public void addToAccessMethods(String name, String accessor, String type) {
		String aMethod = _template.getAccessMethod(name + DATA_CLASS_POSTFIX, accessor, type);
		if (!_methods.contains(aMethod)) {
			_methods += aMethod;
		}
	}

	public String getDefinition() {
		return _template.getComment(_copyright) + _definition + _imports + _clazz + _members
				+ ClassTemplateHelper.cleanLastOccurrence(_constructorHead, ",") + _constructorBody
				+ _template.getCloseConstructor() + _methods + getToXML() + getClone() + _template.getCloseClass()
				+ _template.getClosePackage();
	}
	
	private String getClone() {
		if(!_hasToXML) {
			return "";
		}
		return "		public function clone() : " + _classname+ " {" + 
		AS3Template.NEW_LINE + "			return new " + _classname+READER_CLASS_POSTFIX+"(toXML()).read();" +
		AS3Template.NEW_LINE + _template.getCloseConstructor();
	}

	private String getToXML() {
		if(!_hasToXML) {
			return "";
		}
		String toString = getOpenToXML(_originalClassName);
		boolean containsArray = false;
		for (As3Member member : _memberNames) {
			String field = "";
			if (member.getType().equals("Array")) {
				containsArray = true;
				field = "{arrayToXml(_" + member.getParsedName() + ").children()}";
			} else if (member.getVartype() == AS3Class.VAR_TYPE_CUSTOM) {
				field = getCustomNodeContent(member.getParsedName());
			} else if (member.getVartype() == AS3Class.VAR_TYPE_PCDATA) {
				field = getOpenNode(member.getName()) + getNodeContent(member.getParsedName(), member.getType())
						+ getCloseNode(member.getName());
			} else {
				String insert = toString.substring(0, toString.indexOf(">"));
				insert += " " + member.getName() + "=" + getNodeContent(member.getParsedName(), member.getType());
				toString = insert + toString.substring(toString.indexOf(">"), toString.length());
			}

			toString += field + AS3Template.NEW_LINE + "				";
		}
		toString += getCloseNode(_originalClassName) + ";" + AS3Template.NEW_LINE + _template.getCloseConstructor();
		if (containsArray) {
			toString += createXmlArrayHelper();
		}
		return toString;
	}

	private String createXmlArrayHelper() {
		return "		private function arrayToXml(a : Array) : XML {" + AS3Template.NEW_LINE
				+ "			var s : String = '<root>';" + AS3Template.NEW_LINE + "			for each (var o : Object in a) {"
				+ AS3Template.NEW_LINE + "				s += XML(o['toXML']()).toXMLString();" + AS3Template.NEW_LINE + "			}"
				+ AS3Template.NEW_LINE + "			return new XML(s+'</root>');" + AS3Template.NEW_LINE + "		}"
				+ AS3Template.NEW_LINE + AS3Template.NEW_LINE;
	}

	private String getCustomNodeContent(String parsedName) {
		return "{((_" + parsedName +" != null) ? _"+parsedName+".toXML() : '')}";
	}

	private String getNodeContent(String parsedName, String type) {
		if(type.equals("Boolean")) {
			return "{_"+parsedName+"}";
		} else if(type.equals("String") || type.equals("Object")) {
			return "{((_" + parsedName +" != null) ? _"+parsedName+" : '')}";
		} else {
			return "{((!isNaN(_" + parsedName +")) ? _"+parsedName+" : '')}";
		}
	}

	private String getOpenToXML(String className) {
		return "		public function toXML() : XML {" + AS3Template.NEW_LINE + "			return " + getOpenNode(className);
	}

	private String getOpenNode(String name) {
		return "<" + name + ">";
	}

	private String getCloseNode(String name) {
		return "</" + name + ">";
	}
}